package com.yupi.springbootinit.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.exception.ThrowUtils;
import com.yupi.springbootinit.mapper.SpaceAnalyzeMapper;
import com.yupi.springbootinit.mapper.SpaceMapper;
import com.yupi.springbootinit.model.dto.space.SpaceQueryRequest;
import com.yupi.springbootinit.model.dto.spaceAnalysis.*;
import com.yupi.springbootinit.model.entity.Picture;
import com.yupi.springbootinit.model.entity.Space;
import com.yupi.springbootinit.model.entity.User;
import com.yupi.springbootinit.model.enums.SpaceLevelEnum;
import com.yupi.springbootinit.model.vo.SpaceVO;
import com.yupi.springbootinit.model.vo.UserVO;
import com.yupi.springbootinit.model.vo.spaceAnalyze.*;
import com.yupi.springbootinit.service.PictureService;
import com.yupi.springbootinit.service.SpaceAnalyzeService;
import com.yupi.springbootinit.service.SpaceService;
import com.yupi.springbootinit.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author Administrator
* @description 针对表【space(空间)】的数据库操作Service实现
* @createDate 2025-07-10 16:31:10
*/
@Service
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space>
    implements SpaceAnalyzeService{

    @Resource
    private UserService userService;
    @Resource
    private SpaceService spaceService;
    @Resource
    private PictureService pictureService;

    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceUsageAnalyzeRequest==null,ErrorCode.PARAMS_ERROR);
        if(spaceUsageAnalyzeRequest.isQueryAll() || spaceUsageAnalyzeRequest.isQueryPublic()){
            QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
            boolean admin = userService.isAdmin(loginUser);
            if(!admin){
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权限");
            }
            queryWrapper.select("picSize");
            if(spaceUsageAnalyzeRequest.isQueryPublic()){
                queryWrapper.isNull("spaceId");
            }
            List<Object> pictureObjsList = pictureService.getBaseMapper().selectObjs(queryWrapper);
            long usedSize = pictureObjsList.stream()
                    .mapToLong(res -> res instanceof Long ? (Long) res : 0).sum();
            long usedCount = pictureObjsList.size();
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(usedSize);
            spaceUsageAnalyzeResponse.setMaxSize(null);
            spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
            spaceUsageAnalyzeResponse.setUsedCount(usedCount);
            spaceUsageAnalyzeResponse.setMaxCount(null);
            spaceUsageAnalyzeResponse.setCountUsageRatio(null);
            return spaceUsageAnalyzeResponse;
        }else {
            Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId==null || spaceId<0,ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space==null,ErrorCode.PARAMS_ERROR);

            checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest,loginUser);

            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(space.getTotalSize());
            spaceUsageAnalyzeResponse.setMaxSize(space.getMaxSize());
            Double sizeUsageRatio = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
            spaceUsageAnalyzeResponse.setSizeUsageRatio(sizeUsageRatio);
            spaceUsageAnalyzeResponse.setUsedCount(space.getTotalCount());
            spaceUsageAnalyzeResponse.setMaxCount(space.getMaxCount());
            Double countUsageRatio = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
            spaceUsageAnalyzeResponse.setCountUsageRatio(countUsageRatio);
            return spaceUsageAnalyzeResponse;
        }
    }

    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceCategoryAnalyzeRequest==null,ErrorCode.PARAMS_ERROR);

            QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
            checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequest,loginUser);
            fillAnalyzeQueryWrapper(spaceCategoryAnalyzeRequest,queryWrapper);

            queryWrapper.select("category as category"
                    ,"count(*) as count","sum(picSize) as totalSize")
                    .groupBy("category");
        List<Map<String, Object>> selectedMaps = pictureService.getBaseMapper().selectMaps(queryWrapper);
        List<SpaceCategoryAnalyzeResponse> spaceCategoryAnalyzeResponses = selectedMaps.stream().map(res -> {
            String category = res.get("category") != null ? res.get("category").toString() : "未分类";
            long count = ((Number) res.get("count")).longValue();
            long totalSize = ((Number) res.get("totalSize")).longValue();
            return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
        }).collect(Collectors.toList());
        return spaceCategoryAnalyzeResponses;
    }

    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceTagAnalyzeRequest==null,ErrorCode.PARAMS_ERROR);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        checkSpaceAnalyzeAuth(spaceTagAnalyzeRequest,loginUser);
        fillAnalyzeQueryWrapper(spaceTagAnalyzeRequest,queryWrapper);

        queryWrapper.select("tags");
        List<Object> pictureObjsList = pictureService.getBaseMapper().selectObjs(queryWrapper);
        List<String> tagJsonList = pictureObjsList.stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());
        Map<String, Long> tagCountMap = tagJsonList.stream().flatMap(tagJson -> JSONUtil.toList(tagJson, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
        List<SpaceTagAnalyzeResponse> spaceTagAnalyzeResponseList = tagCountMap.entrySet()
                .stream().sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
        return spaceTagAnalyzeResponseList;
    }

    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceSizeAnalyzeRequest==null,ErrorCode.PARAMS_ERROR);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequest,loginUser);
        fillAnalyzeQueryWrapper(spaceSizeAnalyzeRequest,queryWrapper);

        queryWrapper.select("picSize");
        List<Object> pictureObjsList = pictureService.getBaseMapper().selectObjs(queryWrapper);
        List<Long> picSizeList = pictureObjsList.stream()
                .map(size -> ((Number) size).longValue())
                .collect(Collectors.toList());
        HashMap<String, Long> sizeRange = new HashMap<>();
        sizeRange.put("0-1KB", picSizeList.stream().filter(size -> size >= 0 && size < 1024).count());
        sizeRange.put("1KB-10KB", picSizeList.stream().filter(size -> size >= 1024 && size < 10240).count());
        sizeRange.put("10KB-100KB", picSizeList.stream().filter(size -> size >= 10240 && size < 102400).count());
        sizeRange.put("100KB-1MB", picSizeList.stream().filter(size -> size >= 102400 && size < 1024000).count());
        sizeRange.put(">1Mb", picSizeList.stream().filter(size -> size >10240000).count());

        List<SpaceSizeAnalyzeResponse> spaceSizeAnalyzeResponseList = sizeRange.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
        return spaceSizeAnalyzeResponseList;
    }

    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceUserAnalyzeRequest==null,ErrorCode.PARAMS_ERROR);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        checkSpaceAnalyzeAuth(spaceUserAnalyzeRequest,loginUser);
        fillAnalyzeQueryWrapper(spaceUserAnalyzeRequest,queryWrapper);

        Long userId = spaceUserAnalyzeRequest.getUserId();
        queryWrapper.eq(ObjUtil.isNotNull(userId),"userId",userId);
        String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();
        switch (timeDimension) {
            case "day":
                queryWrapper.select("DATE_FORMAT(createTime, '%Y-%m-%d') as period", "count(*) as count");
                break;
            case "week":
                queryWrapper.select("YEARWEEK(createTime) as period", "count(*) as count");
                break;
            case "month":
                queryWrapper.select("DATE_FORMAT(createTime, '%Y-%m') as period", "count(*) as count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的时间维度");
        }
        queryWrapper.groupBy("period").orderByAsc("period");
        List<Map<String, Object>> pictureMaps = pictureService.getBaseMapper().selectMaps(queryWrapper);
        List<SpaceUserAnalyzeResponse> spaceUserAnalyzeResponseList = pictureMaps.stream().map(map -> {
            String period = map.get("period").toString();
            long count = ((Number) map.get("count")).longValue();
            return new SpaceUserAnalyzeResponse(period, count);
        }).collect(Collectors.toList());
        return spaceUserAnalyzeResponseList;
    }

    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceRankAnalyzeRequest==null,ErrorCode.PARAMS_ERROR);

        if(!userService.isAdmin(loginUser)){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权限");
        }
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","spaceName","userId","totalSize")
                .orderByDesc("totalSize")
                .last("limit "+spaceRankAnalyzeRequest.getTopN());
        return spaceService.list(queryWrapper);
    }

    @Override
    public void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest, User loginUser) {
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        boolean queryAll = spaceAnalyzeRequest.isQueryAll();
        boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
        if(queryAll || queryPublic){
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR,"无权限");
        }
        else {
            ThrowUtils.throwIf(spaceId==null || spaceId<0,ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space==null,ErrorCode.PARAMS_ERROR);
            spaceService.checkSpaceAuth(space,loginUser);
        }
    }



    private void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest
            , QueryWrapper<Picture> queryWrapper) {
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        boolean queryAll = spaceAnalyzeRequest.isQueryAll();
        boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
        if(queryAll){
            return;
        }
        if(queryPublic){
            queryWrapper.isNull("spaceId");
            return;
        }
        if(spaceId!=null && spaceId>0) {
            queryWrapper.eq("spaceId", spaceId);
            return;
        }
        throw new BusinessException(ErrorCode.PARAMS_ERROR);
    }
}




